/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package algoritmosgenetico;

/**
 *
 * @author gbula
 */
public class OperadoresGeneticos {

    private int tam;
    private int nw;
    private int[][] pobInicial;
    private double[] fi;
    private int[][] pobFinal;
    private double pm;    

    public OperadoresGeneticos(Poblacion p,double pm) {
        this.tam = p.getIndividuos().length;
        nw=p.getIndividuos()[0].length;
        this.pobInicial = new int[tam][nw];
        this.fi=new double[tam];
        for (int i = 0; i < tam; ++i) {
            for (int j = 0; j < pobInicial[i].length; ++j) {
                pobInicial[i][j] = p.getIndividuos()[i][j];
            }
            fi[i]=p.getFitnessValues()[i];
        }        
        this.pm = pm;
        evolucionar();
    }

    public void evolucionar() {
        pobFinal = new int[tam][nw];
        int te=4;
        int[][] elite=elitismo(te);
        for(int i=0;i<te;++i){
            pobFinal[i]=elite[i];
        }
        int[][] padres = seleccionarPadres(tam-te);
        for (int c = 1; c <= (tam-te) / 2; c++) {
            int[][] ch = cruzamiento2(padres[c - 1][0], padres[c - 1][1]);
            pobFinal[(c-1)*2+te] = ch[0];
            pobFinal[(c-1) * 2 + 1+te] = ch[1];
        }
    }
    
        private int[][] elitismo(int te) {
        int[][] eliteAux = new int[te][nw];
        Solucion[] ordenados = new Solucion[tam];
        for (int i = 0; i < tam; ++i) {
            ordenados[i] = new Solucion(pobInicial[i],fi[i]);
        }
        java.util.Arrays.sort(ordenados, new SolucionComparator());
        int inc = 0;
        int j = 0;
        double distActual = 0;
        while (inc < te) {
            if (distActual != ordenados[j].getFuncion()) {
                distActual = ordenados[j].getFuncion();
                eliteAux[inc] = ordenados[j].getIndividuo();
                inc = inc + 1;
            }
            j = j + 1;
        }
        return eliteAux;
    }

    public int[][] seleccionarPadres(int np) {
        int[][] p = new int[(np / 2)][2];
        for (int i = 0; i < p.length; i++) {
            java.util.Vector v = new java.util.Vector();
            for (int k = 0; k < tam; ++k) {
                v.add(new Integer(k));
            }
            int a = (int) (Math.random() * v.size());
            int pos1 = Integer.parseInt(v.get(a).toString());
            v.remove(a);
            a = (int) (Math.random() * v.size());
            int pos2 = Integer.parseInt(v.get(a).toString());
            v.remove(a);
            p[i][0] = pos1;
            p[i][1] = pos2;
        }
        return p;
    }

    public int[][] cruzamiento2(int p1, int p2) {
        int[][] padres = new int[2][nw];
        padres[0] = pobInicial[p1];
        padres[1] = pobInicial[p2];
        int[][] whHijos = new int[2][padres[0].length];
       int puntoCorte=(int) Math.floor(padres[0].length/3);
       for(int j=0;j<padres[0].length;++j){
            if(j<puntoCorte){
                whHijos[0][j] = padres[0][j];
                whHijos[1][j] = padres[1][j];
            }else if(j>=(padres[0].length-puntoCorte)){
                whHijos[0][j] = padres[0][j];
                whHijos[1][j] = padres[1][j];
            }else{
                whHijos[0][j] = padres[1][j];
                whHijos[1][j] = padres[0][j];
            }
        }
        
        /**for (int j = 0; j < padres[0].length; ++j) {
            if (Math.random()>0.5) {
                whHijos[0][j] = padres[0][j];
                whHijos[1][j] = padres[1][j];
            } else {
                whHijos[0][j] = padres[1][j];
                whHijos[1][j] = padres[0][j];
            }
        }**/
       
        int[][] hijos = new int[2][padres[0].length];
        whHijos[0] = repararWH(whHijos[0]);
        whHijos[1] = repararWH(whHijos[1]);
        System.arraycopy(whHijos[0],0, hijos[0],0, whHijos[0].length);
        System.arraycopy(whHijos[1],0, hijos[1],0, whHijos[1].length);
        for (int i = 0; i < 2; ++i) {
            if (Math.random() < pm) {
                hijos[i] = mutation(hijos[i]);
            }
        }
        return hijos;
    }

    public int[] repararWH(int[] s) {
        int[] wr = new int[s.length];
        System.arraycopy(s, 0, wr, 0, wr.length);
        int sumaw = 0;
        java.util.Vector v = new java.util.Vector();
        int j = 0;
        for (int i = 0; i < s.length; ++i) {
            if (s[i] == 1) {
                sumaw = sumaw + 1;
            } else {
                v.add(j, new Integer(i));
                j = j + 1;
            }
        }
        while (sumaw < 1) {
            int a = (int) (Math.random() * v.size());
            int pos = Integer.parseInt(v.get(a).toString());
            wr[pos] = 1;
            sumaw = sumaw + 1;
            v.remove(a);
        }
        return wr;
    }

    public int[] mutation(int[] s) {
        int[] wr = new int[s.length];
        System.arraycopy(s, 0, wr, 0, wr.length);
        java.util.Vector ones = new java.util.Vector();
        java.util.Vector zeroes = new java.util.Vector();
        for (int i = 0; i < wr.length; ++i) {
            if (wr[i] == 1) {
                ones.add(new Integer(i));
            } else {
                zeroes.add(new Integer(i));
            }
        }
        if (ones.size() != wr.length) {
            int a = (int) (Math.random() * ones.size());
            int pos = Integer.parseInt(ones.get(a).toString());
            wr[pos] = 0;
            a = (int) (Math.random() * zeroes.size());
            pos = Integer.parseInt(zeroes.get(a).toString());
            wr[pos] = 1;
        }
        return wr;
    }

    public int[][] getPobFinal() {
        return pobFinal;
    }
    }
